﻿/***********************************************************************************************
 * 
 * ProjectName: WMSSoft.Lib.WinKStart
 * 
 * Description: Class to read startmenu - items from Disk
 * 
 * Created:     10.05.2012
 * 
 * Author:      matthias wagler - matthias@WMSSoft.de
 * 
 * Copyright:   Copyright 2012 by WMSSoft.de
 * 
 * License:     GPLv3
 * 
 * History:     10.05.2012 - matthias wagler matthias@WMSSoft.de   -   Created
 * 
 **********************************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WMSSoft.Lib.Basic;
using WMSSoft.Lib.Enums;

namespace WMSSoft.Lib.WinKStart
{
    /// <summary>
    /// Class to read Windowsstartmenu from Disk and prepare it as a List from MenuItems and subitems.
    /// The Startmenu - Location gets from Windows - Spezial Folders.
    /// </summary>
    public class cStartmenuReader
    {
        //Locations for Startmenu folder
        //Windows 8
        //C:\ProgramData\Microsoft\Windows\Start Menu\Programs
        private const string WINDOWS7_STARTMENU_SUBFOLDER = @"Microsoft\Windows\Start Menu\Programs";
        private string m_UserStartMenuPath = "";
        private string m_AllUsersStartMenuPath = "";
        private bool m_ReadAllUserItems = true;

        private Dictionary<string, object> _StartmenuItems = null;
        private cStartmenuItem _RootStartMenuItem = null;
        private static cStartmenuItem m_Thread_RootStartMenuItem = null;

        private Thread m_StartMenuReader_Thread = null;

        private event EventHandler ThreadDone;
        public event EventHandler UpdateMenuItems;

        /// <summary>
        /// This Property allow Access to the readed startmenuitems. This Property is ReadOnly
        /// </summary>
        public cStartmenuItem StartMenuRootItem
        {
            get { return _RootStartMenuItem; }
        }

        /// <summary>
        /// Erstellt eine Instanz der Klasse
        /// </summary>
        public cStartmenuReader()
        {
            try
            {
                //init dictionary
                m_UserStartMenuPath = System.Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);
                m_UserStartMenuPath = System.IO.Path.Combine(m_UserStartMenuPath, "Programs");
                m_AllUsersStartMenuPath = System.Environment.GetFolderPath(Environment.SpecialFolder.CommonStartMenu);
                m_AllUsersStartMenuPath = System.IO.Path.Combine(m_AllUsersStartMenuPath, "Programs");

                ThreadDone += cStartmenuReader_ThreadDone;
                _StartmenuItems = new Dictionary<string, object>();
                _RootStartMenuItem = new cStartmenuItem("root", "Startmenu", eLinkExecutionTypes.Program, "", eExecutionProcedure.Unknown,
                                                        eItemType.Root, "", null, null, "", "", m_UserStartMenuPath, m_AllUsersStartMenuPath);
            }
            catch (Exception Ex)
            {
                throw new Exception("Error while initialising Startmenureader!", Ex);
            }
        }

        #region Properties

        public bool ReadAllUserItems
        {
            get { return m_ReadAllUserItems; }
            set { m_ReadAllUserItems = value; }
        }

        #endregion

        void cStartmenuReader_ThreadDone(object sender, EventArgs e)
        {
            //_RootStartMenuItem = m_Thread_RootStartMenuItem;
            m_Thread_RootStartMenuItem = null;

            //m__UpdadeTimer.Start();
            if (UpdateMenuItems != null) UpdateMenuItems(this, EventArgs.Empty);
        }

        /// <summary>
        /// Methode load the WindowsStartmenu From Disk
        /// </summary>
        /// <returns>StartMenuRootItem</returns>
        public cStartmenuItem  LoadStartmenu()
        {
            try
            {
                //code to read the windows startmenu
                //string sStartMenuBasicPath = System.Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);

                cStartmenuItem myProgramsFolderItem = cStartmenuItem.MakeInstance(m_UserStartMenuPath, 
                                                                                  _RootStartMenuItem);
                _RootStartMenuItem.AddChild(myProgramsFolderItem);

                //SearchStartmenuItems(_UserStartMenuPath, myProgramsFolderItem);
                SearchStartmenuItems("", myProgramsFolderItem);
                //SearchStartmenuItemsRecursiv(sStartMenuBasicPath,  _RootStartMenuItem);
                
                //read only logged on user startmenuitem or also Items for all users
                if (m_ReadAllUserItems == true)
                {
                    //sStartMenuBasicPath = System.Environment.GetFolderPath(Environment.SpecialFolder.CommonStartMenu);
                    //cStartmenuItem myAllUsersProgramsFolderItem = myProgramsFolderItem.Copy();
                    //myAllUsersProgramsFolderItem.BasicPath = System.IO.Path.Combine(sStartMenuBasicPath, "Programs");
                    //SearchStartmenuItems(_AllUsersStartMenuPath, myProgramsFolderItem);
                    SearchStartmenuItems("", myProgramsFolderItem);
                    //SearchStartmenuItemsRecursiv(sStartMenuBasicPath, _RootStartMenuItem);
                    
                }
                
                //return a link to the StartMenuRootItem
                return _RootStartMenuItem;
            }
            catch (Exception Ex)
            {
                //write error to messagebus
                CMessagelogging.AppendMessage("Error while loading Startmenu from disk!", Ex, EMessageTypes.Error);
                return null;
            }
        }

        /// <summary>
        /// Methode load the WindowsStartmenu From Disk and use a own thread
        /// </summary>
        /// <returns>StartMenuRootItem</returns>
        public cStartmenuItem Load()
        {
            try
            {
                m_Thread_RootStartMenuItem = _RootStartMenuItem;

                Thread m_StartMenuReader_Thread = new Thread(ThreadMthode_LoadStartmenu);
                m_StartMenuReader_Thread.Start();

                return _RootStartMenuItem;
            }
            catch (Exception Ex)
            {
                return null;
            }
        }

        void ThreadMthode_LoadStartmenu()
        {
            try
            {

                cStartmenuItem myProgramsFolderItem = cStartmenuItem.MakeInstance(m_UserStartMenuPath,
                                                                                  m_Thread_RootStartMenuItem);
                m_Thread_RootStartMenuItem.AddChild(myProgramsFolderItem);

                SearchStartmenuItemsRecursiv(m_UserStartMenuPath, myProgramsFolderItem);

                //read only logged on user startmenuitem or also Items for all users
                if (UserSettingsReader.MenuItemSettings.ShowAllUsers == true)
                {
                    SearchStartmenuItemsRecursiv(m_AllUsersStartMenuPath, myProgramsFolderItem);
                }
            }
            catch (Exception Ex)
            {
                //write error to messagebus
                CMessagelogging.AppendMessage("Error while loading Startmenu from disk!", Ex, EMessageTypes.Error);                
            }
            finally
            {        
                _RootStartMenuItem = m_Thread_RootStartMenuItem;
                m_Thread_RootStartMenuItem = null;
                m_StartMenuReader_Thread = null;
                if (ThreadDone != null) ThreadDone(null, EventArgs.Empty);
            }
        }

        /// <summary>
        /// The Methode read all Files an directories (with all Subdirectories) from his given path
        /// </summary>
        /// <param name="Startfolder">Path to search from</param>
        /// <param name="Parent">Parent to add childs</param>
        public static void SearchStartmenuItemsRecursiv(string Startfolder, cStartmenuItem Parent)
        {
            try
            {
                string[] DirFiles = System.IO.Directory.GetFiles(Startfolder);
                cStartmenuItem myStartmenuItem = null;
                foreach (string File in DirFiles)
                {
                    if (Parent != null)
                    {
                        myStartmenuItem = cStartmenuItem.MakeInstance(File, Parent );

                        if (myStartmenuItem != null)
                        {
                            //add this Item as child to parent item
                            Parent.AddChild(myStartmenuItem);                           
                        }
                    }
                }

                //read directories
                string[] myDirectories = System.IO.Directory.GetDirectories(Startfolder);
                foreach (string Directory in myDirectories)
                {
                    if (Parent != null)
                    {
                        myStartmenuItem = cStartmenuItem.MakeInstance(Directory, Parent );
                        if (myStartmenuItem != null)
                        {
                            Parent.AddChild(myStartmenuItem);                            
                             
                            SearchStartmenuItemsRecursiv(Directory,
                                                        (cStartmenuItem)Parent.ChildItems[myStartmenuItem.ItemName.ToUpper()]);

                        }
                        
                    }
                }

            }
            catch (Exception Ex)
            {
                CMessagelogging.AppendMessage("Error while reading startmenuitems!", Ex, EMessageTypes.Error);
            }
        }

        /// <summary>
        /// The Methode read all Files an directories (without all Subdirectories) from his given path
        /// </summary>
        /// <param name="Startfolder">Path to search from</param>
        /// <param name="Parent">Parent to add childs</param>
        public static void SearchStartmenuItems(string Startfolder, cStartmenuItem Parent)
        {
            try
            {
                //read all userstartmenu item
                string[] DirFiles = null;
                cStartmenuItem myStartmenuItem = null;
                string[] myDirectories = null;

                if (System.IO.Directory.Exists(System.IO.Path.Combine(Parent.UserStartMenuPath, Startfolder)) == true)
                {
                    DirFiles = System.IO.Directory.GetFiles(System.IO.Path.Combine(Parent.UserStartMenuPath, Startfolder));
                   
                    foreach (string File in DirFiles)
                    {
                        if (Parent != null)
                        {
                            myStartmenuItem = cStartmenuItem.MakeInstance(File, Parent);

                            if (myStartmenuItem != null)
                            {
                                //add this Item as child to parent item
                                Parent.AddChild(myStartmenuItem);
                            }
                        }
                    }
                }

                //read allusersstartmenu items
                DirFiles = null;
                if (System.IO.Directory.Exists(System.IO.Path.Combine(Parent.AllUsersStartMenuPath, Startfolder)) == true)
                {
                    DirFiles = System.IO.Directory.GetFiles(System.IO.Path.Combine(Parent.AllUsersStartMenuPath, Startfolder));
                    myStartmenuItem = null;
                    foreach (string File in DirFiles)
                    {
                        if (Parent != null)
                        {
                            myStartmenuItem = cStartmenuItem.MakeInstance(File, Parent);

                            if (myStartmenuItem != null)
                            {
                                //add this Item as child to parent item
                                Parent.AddChild(myStartmenuItem);
                            }
                        }
                    }
                }

                if (System.IO.Directory.Exists(System.IO.Path.Combine(Parent.UserStartMenuPath, Startfolder)) == true)
                {
                    //read userstartmenu directories
                    myDirectories = System.IO.Directory.GetDirectories(System.IO.Path.Combine(Parent.UserStartMenuPath, Startfolder));
                    foreach (string Directory in myDirectories)
                    {
                        if (Parent != null)
                        {
                            myStartmenuItem = cStartmenuItem.MakeInstance(Directory, Parent);
                            if (myStartmenuItem != null)
                            {
                                Parent.AddChild(myStartmenuItem);
                                //Search only the items in given folder
                                //SearchStartmenuItemsRecursiv(Directory,
                                //                            (cStartmenuItem)Parent.ChildItems[myStartmenuItem.ItemName.ToUpper()]);

                            }

                        }
                    }
                }

                //read allusersstartmenu directories
                if (System.IO.Directory.Exists(System.IO.Path.Combine(Parent.AllUsersStartMenuPath, Startfolder)) == true)
                {
                    myDirectories = null;
                    myDirectories = System.IO.Directory.GetDirectories(System.IO.Path.Combine(Parent.AllUsersStartMenuPath, Startfolder));
                    foreach (string Directory in myDirectories)
                    {
                        if (Parent != null)
                        {
                            myStartmenuItem = cStartmenuItem.MakeInstance(Directory, Parent);
                            if (myStartmenuItem != null)
                            {
                                Parent.AddChild(myStartmenuItem);
                                //Search only the items in given folder
                                //SearchStartmenuItemsRecursiv(Directory,
                                //                            (cStartmenuItem)Parent.ChildItems[myStartmenuItem.ItemName.ToUpper()]);

                            }

                        }
                    }
                }

            }
            catch (Exception Ex)
            {
                CMessagelogging.AppendMessage("Error while reading startmenuitems!", Ex, EMessageTypes.Error);
            }
        }

    }
}
